/*
 *  interface.h
 *  EPPI-0.0
 *
 *  Created by Juan Carlos Garcia Orden on 15/11/07.
 *
 */

#ifndef _interface_h_
#define _interface_h_

#include <iostream>
#include <vector>
#include "point.h"
#include "process.h"
#include "mecsystem.h"
#include "point.h"

#include "mpi.h"

using namespace std;

//extern int rankk;

class Process;

class Interface
{
public:
	int lProc, rProc;				/** Number of local and remote processes respectively */
	Process* localProc;				/** Pointer to the local process */
	int relatedInterfaceNum;		/** Number of the related interface at remote process */
	bool isSynchronized;			/** true if sinchronized with its related interface */
	vector<string> pointNames;		/** Names of the interface points */
	vector<Point*> pointP;			/** Local pointers to the interface points */
	vector<double> resExt;				/** External residual */
	vector< vector<double> > tangExt;	/** External tangent */
	vector<double> resInt;				/** Internal residual */
	vector< vector<double> > tangInt;	/** Internal tangent */
	int numDofs;					/** Number of dofs of the interface*/
	int numDofsP;					/** Number of dofs of the parent process */
	int numDofsI;					/** Number of interior dofs: numDofsI = numDofsP-numDofs */
	int numDofsIP;					/** Number of interior dofs of the parent process */
	int numDofsB;					/** Number of dofs in other boundaries of this process */
	vector<int> localGlob;			/** Given a local dof, gives a global dof number of a boundary point */
	vector<int> localGlobI;			/** Given a local dof, gives a global dof number of an interior point */
	vector<Interface*> vOtherInter;	/** Vector of pointers to the other interfaces of the local process */
	vector<double> kAux;
	vector<double> kAuxp;
	vector<vector<double> > KIB;	/** Tangent matrix of interior - boundary dofs */
	vector<vector<double> > KBI;	/** Tangent matrix of boundary - interior dofs UNCOMMENT FOR UNSYMMETRIC MATRICES */
	vector<vector<double> > KBB;	/** Tangent matrix of boundary - boundary dofs */
	vector<double> RB;				/** Residual vector of boundary dofs */
	vector<vector<double> > Y0;
	vector<vector<double> > Y0ori;
	vector<vector<double> > YB;
//	vector<vector<double> > YBori;
	vector<vector<double> > B0;
	vector<vector<double> > KIB2;
	vector<vector<double> > KIB2copia;
	vector<vector<double> > KBI2;	/** UNCOMMENT FOR UNSYMMETRIC MATRICES */
	vector<vector<double> > KBB2;
//	vector<vector<double> > KBB2copia;
	vector<int> globalLocal;
	vector<int> globalLocalI;
	vector<int> globalLocalII;
	vector<int> localGlobIII;
	vector<int> globalLocalIII;
	vector<vector<int> > otherLocalGlob;
	MPI::Request request[2];
	MPI::Status status[2];
	bool symmFlag;
	bool isMassSynchronized;			/** true if lumped mass is sinchronized with its related interface */
//	vector<double> mLumpedLocal;

//	double* rhsb;
//	double* rhsx;
//	double	*ferr, *berr;
//	double* rhsb;
	SuperMatrix	B_temp;
//	double* rhsbX;
	SuperMatrix	X_temp;
	
	int tam;
	bool isKResAlreadyComputed;
	
	
public:
	Interface();
	Interface(int, int, const int&, Process*);
	~Interface();
	
	void fillPointNames();			/** Names of the interface points, local and non local */
	bool checkRelation(int, int);	/** Check if two interfaces are related. */
	void setRemoteInterface();		/** Set the pointer to the remote interface */
	void synchronize();				/** Synchronize the vector pointNames of the two interfaces */
	void subsPointNames(const vector<string>&);		/** Substitute pointNames vector by the input vector */
	void getPointers();				/** Get local pointers from the point names */
	void calcTangResExt(sparseMatrix&, bool);
	void initializeKR(vector<vector<double> >&, vector<vector<double> >&, vector<vector<double> >&,
						vector<int>&, vector<int>&,
						vector<double>&, sparseMatrix&, int&);
	void setInterExt(vector<vector<double> >&, vector<vector<double> >&, vector<vector<double> >&,
						vector<int>&, vector<int>&,
						vector<double>&, sparseMatrix&, int&, bool);		
	void setInterExtNew(vector<vector<double> >&, vector<vector<double> >&, vector<vector<double> >&,
						 vector<int>&, vector<int>&,
						 vector<double>&, sparseMatrix&, int&, bool);	
	void setInterInt();
	void resetInterInt();
	void calcSize();							/** calc number of dofs of the interface */
	void setSize();								/** set number of dofs of the interface */
	void addRes(vector<double>&);			/** Add contribution of interface to residual */
	void addTang(vector<vector<double> >&, vector<vector<double> >&, vector<vector<double> >&,
				 vector<int>&, vector<int>&,
				 int&);						/** Add contribution of interface to tangent */
	void setOtherInter(vector<Interface*>);		/** Set vector vOtherInter */
	void extrude();
	void unextrude();
	bool checkIfDof(const int);					/** Check if global dof i belongs to the interface */
	void solveKII(sparseMatrix&, bool);		/** Efficiently solve for the Kii matrix.*/
	
	// For explicit integrators
	void setSizeExp();
	void initializeRExp(vector<double>&);
	void setInterIntExp();
	void addResExp(vector<double>&);
	void synchronizeMass(vector<double>&);
	
	// Friend functions
	friend void printSTLVector(vector<double>& v);
	friend void printSTLVector(vector<int>& v);
	friend void printSTLVector(const vector<string>& v);
	friend void printSTLMatrix(const vector< vector<double> >& m);
	friend double lTwoNorm(const vector<double>& v1, const vector<double>& v2);
	friend void lu(vector<vector<double> >&);
	friend void forSub(vector<vector<double> >& mat, vector<vector<double> >& mat_r);
	friend void backSub(vector<vector<double> >& mat, vector<vector<double> >& mat_r);
	friend void setZero(vector< vector<double> >& m);
	friend int locateInSparse(vector<int>& ia, vector<int>& ja, int& I, int& J);
	
//	friend SuperMatrix convert_stl_SLU(vector<vector<double> >&);
//	friend void convert_SLU_stl(SuperMatrix&, vector<vector<double> >&);


};

#endif
